package eu.telecombretagne.rsm.network.utils;

import java.io.IOException;
import java.net.BindException;
import java.net.ServerSocket;

import eu.telecombretagne.rsm.gui.NameConsts;
import eu.telecombretagne.rsm.gui.frames.DesktopFrame;

public class ServerManager {
	
	private static final Integer networkPortBase = 9696;
	private static Integer networkPortCurrent = 9696;
	
	private static final Integer networkPortLimit = 10;
	private static Integer tryCounter = 0;
	
	private static ServerSocket serverSocket;
	
	/**
	 * Gets a server socket.
	 * 
	 * @return Returns a current server socket object.
	 * @throws BindException
	 */
	public static ServerSocket getServerSocket() throws BindException{		
		createServer();
		
		DesktopFrame.writeLogNetwork(NameConsts.NETWORKISUPPORTNUMBER + serverSocket.getLocalPort() + ".");
		
		return serverSocket;
	}
	
	private static ServerSocket createServer() throws BindException{
		DesktopFrame.writeLogNetwork(NameConsts.STARTINGASOCKETSERVERONAPORT + networkPortCurrent + ".");
		
		try {
			serverSocket = new ServerSocket(networkPortCurrent);
			serverSocket.setReuseAddress(true);
			
		} catch (BindException be) {
			DesktopFrame.writeLogNetwork(NameConsts.APORT + networkPortCurrent + NameConsts.ISALREADYINUSE);
			
			if(assertTryCreateServer()){
				getNextNetworkPort();
				serverSocket = createServer();
			} else {
				throw new BindException();
			}
		} catch (IOException ioe) {
			DesktopFrame.writeLogError(NameConsts.EXCEPTION + ioe);
			ioe.printStackTrace();
		}
		
		return serverSocket;
	}
	
	private static Integer getNextNetworkPort(){
		if(networkPortCurrent < networkPortBase + networkPortLimit){
			networkPortCurrent++;
		} else {
			networkPortCurrent = networkPortBase;
		}
		
		return networkPortCurrent;
	}
	
	private static Boolean assertTryCreateServer(){
		Boolean assertTry = false;
		
		if(tryCounter < networkPortLimit){
			tryCounter++;
			assertTry = true;
		}
		
		return assertTry;
	}
	
	/**
	 * Gets a current value of a network port.
	 * @return Returns an Integer value of a network port.
	 */
	public static Integer getNetworkPort(){
		return networkPortCurrent;
	}
}